package Personajes;

import Mundo.*;
import Objetos.*;
import java.util.*;
import Personajes.Personaje.*;
import java.awt.*;
import java.awt.image.*;
import java.io.Serializable;

public class Batallon implements Serializable {

    private int x;
    private int y;
    private String nombre;
    private int numPersonajes = 0;
    private int atkTot;
    private int defTot;
    private int bando;
    private boolean tieneHeroe;
    public Personaje[] personajes = new Personaje[40];
    private boolean activo;
    private boolean muerto = false;
    transient private BufferedImage sprite;
    transient public static ArrayList<BufferedImage> sprites;

    public BufferedImage getSprite() {
        return sprite;
    }

    public void setSprite(Mapa map) {
        Personaje p = detectarMasFuerte();
        if (p == null) {
            return;
        }
        this.sprite = sprites.get((9 * this.bando) + p.tipo);
        map.celdas[this.y][this.x].setSprite(sprite);

    }

    public int cure() {
        boolean hayrabona = false;
        for (int i = 0; i < this.numPersonajes; i++) {
            if (personajes[i].tipo == 1) { //si hay rabona
                hayrabona = true;
            }
        }
        int difHP = 0;
        if (hayrabona) {
            for (int i = 0; i < this.numPersonajes; i++) {
                difHP = difHP + personajes[i].curar(Rabona.factorCuracion);
            }
        }
        return difHP;
    }

    public void setBando(int bando, Mapa map) {
        this.bando = bando;
        map.celdas[y][x].setSprite(sprite);
        if (this.bando == 0) {
            map.celdas[y][x].setElementoEnCelda('P');
        } else {
            if (this.bando == 1) {
                map.celdas[y][x].setElementoEnCelda('R');
            } else {
                map.celdas[y][x].setElementoEnCelda('A');
            }
        }
    }

    public void setMuerto(boolean muerto, Mapa map) {
        this.muerto = muerto;
        map.celdas[this.y][this.x].setElementoEnCelda(' ');
        map.celdas[this.y][this.x].setSprite(null);
        this.x = 0;
        this.y = 0;
    }

    public boolean isMuerto() {
        return muerto;
    }

    public int getBando() {
        return bando;
    }

    public Personaje[] getPersonajes() {
        return personajes;
    }

    public boolean getTieneHeroe() {
        return tieneHeroe;
    }

    public int getNumPersonajes() {
        return numPersonajes;
    }

    public void setNumPersonajes(int numPersonajes) {
        this.numPersonajes = numPersonajes;
    }

    public int getAtkTot() {
        return atkTot;
    }

    public void setAtkTot(int atkTot) {
        this.atkTot = atkTot;
    }

    public int getDefTot() {
        return defTot;
    }

    public void setDefTot(int defTot) {
        this.defTot = defTot;
    }

    public Batallon(String nombre, int bando, Personaje[] personajes, int x, int y, int numPersonajes, Mapa mapa) {
        this.nombre = nombre;
        this.x = x;
        this.y = y;
        this.activo = true;
        this.atkTot = 0;
        this.defTot = 0;
        this.numPersonajes = numPersonajes;
        this.bando = bando;
        switch (bando) {
            case 0:
                mapa.celdas[y][x].setElementoEnCelda('P');
                break;
            case 1:
                mapa.celdas[y][x].setElementoEnCelda('R');
                break;
            case 2:
                mapa.celdas[y][x].setElementoEnCelda('A');
                break;
        }

        for (int i = 0; i < this.numPersonajes; i++) {
            this.atkTot = this.atkTot + personajes[i].getAtk();
            this.defTot = this.defTot + personajes[i].getDef();
        }
        for (int i = 0; i < this.numPersonajes; i++) {
            if (personajes[i].tipo == 0) {
                this.tieneHeroe = true;
            }
        }
    }

    public Batallon(ArrayList<Personaje> personajes) {
        Personaje[] p = new Personaje[30];
        personajes.toArray(p);
        this.personajes = p;
        this.numPersonajes = personajes.size();
        //this.setSprite();
    }

    public Batallon(String nombre, int bando, int x, int y, int numPersonajes, Mapa mapa) {
        //este no tiene un arreglo de soldados... no se porque tienen uno que
        //pide un arreglo de soldados es mas dificil manejar
        this.nombre = nombre;
        this.x = x;
        this.y = y;
        this.activo = true;
        this.atkTot = 0;
        this.defTot = 0;
        this.numPersonajes = numPersonajes;
        this.bando = bando;
        //this.setSprite();
        mapa.celdas[y][x].setSprite(sprite);
        switch (this.bando) {
            case 0:
                mapa.celdas[y][x].setElementoEnCelda('P');
                break;
            case 1:
                mapa.celdas[y][x].setElementoEnCelda('R');
                break;
            case 2:
                mapa.celdas[y][x].setElementoEnCelda('A');
                break;
        }
        for (int i = 0; i < this.numPersonajes; i++) {
            this.atkTot = this.atkTot + personajes[i].getAtk();
            this.defTot = this.defTot + personajes[i].getDef();
        }
        for (int i = 0; i < this.numPersonajes; i++) {
            if (personajes[i].tipo == 0) {
                this.tieneHeroe = true;
            }
        }
    }

    public String getNombre() {
        return this.nombre;
    }

    public boolean getActivo() {
        return activo;
    }

    public void setActivo(boolean activo) {
        this.activo = activo;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public String imprime_resumen() {
        String resumen = "";
        int cantxtipo[] = new int[Personaje.num_distintos];
        int hpxtipo[] = new int[Personaje.num_distintos];
        this.getpersonajesxtipo(cantxtipo, hpxtipo);

        resumen = resumen + "Detalle del Batallon \n";
        for (int i = 0; i < Personaje.num_distintos; i++) {
            if (cantxtipo[i] > 0) {
                resumen = resumen + Personaje.tipos[i] + " = " + cantxtipo[i];// + '\n';
                //}
                //if (hpxtipo[i] > 0) {
                resumen = resumen + "   HP " + hpxtipo[i] + '\n';
            }
        }
        //System.out.println("Ataque = " + this.getAtkTot() + '\t' + "Defensa = " + this.getDefTot());
        return resumen;

    }

    public String[] obtener_detalle(){


        int cantxtipo[] = new int[Personaje.num_distintos];
        int hpxtipo[] = new int[Personaje.num_distintos];
        this.getpersonajesxtipo(cantxtipo, hpxtipo);
        String resumen[] = new String[this.get_numper()];
        int a=0;

        for (int i = 0; i < Personaje.num_distintos; i++) {
            if (cantxtipo[i] > 0) {
                resumen[a] =Personaje.tipos[i] + " x " + cantxtipo[i] + '\n';
                //}
                //if (hpxtipo[i] > 0) {
                resumen[a] = resumen[a] + "   HP " + hpxtipo[i] + '\n';
                a++;
            }
        }
        //System.out.println("Ataque = " + this.getAtkTot() + '\t' + "Defensa = " + this.getDefTot());
        return resumen;

    }

    public int[] get_tipos(){

        int cantxtipo[] = new int[Personaje.num_distintos];
        int hpxtipo[]=new int[Personaje.num_distintos];

        getpersonajesxtipo(cantxtipo, hpxtipo);
        return cantxtipo;

    }

    public int get_numper(){

        int i=0;
        int cantxtipo[] = new int[Personaje.num_distintos];
        int hpxtipo[]=new int[Personaje.num_distintos];
        getpersonajesxtipo(cantxtipo, hpxtipo);
        for(int a=0; a<Personaje.num_distintos;a++){

            if (cantxtipo[a]>0) i++;

        }

        return i;
    }



  public synchronized void recluta(Batallon nat, int tipo, int num, Mapa mapa){


        for (int i=0; num>0 && i<=nat.numPersonajes;i++){

            if (num>0 && nat.getPersonajes()[i].get_tipo()== tipo){

                this.agregarPersonaje(nat.sacarPersonaje(i));
                num--;
                i=-1;
            }


        }

        if (nat.numPersonajes==0) nat.setMuerto(muerto, mapa);
        
    }












    public void imprime_resumen(Graphics g, int[] coord) {
        int cantxtipo[] = new int[Personaje.num_distintos];
        int hpxtipo[] = new int[Personaje.num_distintos];
        this.getpersonajesxtipo(cantxtipo, hpxtipo);
        g.drawString("Detalle del Batallon", 20 * (coord[1] + 1) + 20, 20 * (coord[0] + 1) + 50);
        coord[0]++;
        for (int i = 0; i < Personaje.num_distintos; i++) {
            if (cantxtipo[i] > 0) {
                g.drawString(Personaje.tipos[i] + " = " + cantxtipo[i] + "   HP " + hpxtipo[i], 20 * (coord[1] + 1) + 20, 20 * (coord[0] + 1) + 50);
                coord[0]++;
            }
        }
        g.drawString("Ataque = " + this.getAtkTot() + "  Defensa = " + this.getDefTot(), 20 * (coord[1] + 1) + 20, 20 * (coord[0] + 1) + 50);
        coord[0]++;
    }

    public void getpersonajesxtipo(int[] cantxtipo, int[] hpxtipo) {
        int hpt;
        for (int i = 0; i < Personaje.num_distintos; i++) {
            cantxtipo[i] = 0;
            hpxtipo[i] = 0;
        }
        for (int i = 0; i < this.numPersonajes; i++) {
            cantxtipo[personajes[i].tipo]++;
            hpxtipo[personajes[i].tipo] += personajes[i].hp;
        }

    }

    public int agregarPersonaje(Personaje personaje) {
        if (this.numPersonajes < 50) {
            this.personajes[this.numPersonajes] = personaje;
            this.numPersonajes++;
            if (personaje.tipo == 0) {
                this.tieneHeroe = true;
            }
            this.atkTot = this.atkTot + personaje.getAtk();
            this.defTot = this.defTot + personaje.getDef();
            return 1;
        } else {
            return 0;
        }
    }

    public Personaje sacarPersonaje(int posi) {
        Personaje aux;
        aux = this.personajes[posi];
        this.atkTot = this.atkTot - aux.getAtk();
        this.defTot = this.defTot - aux.getDef();
        this.personajes[posi] = this.personajes[this.numPersonajes - 1];
        this.personajes[this.numPersonajes - 1] = null;
        if (aux.tipo == 0) {
            this.tieneHeroe = false;
        }
        numPersonajes--;
        return aux;
    }

    public void mover(Mapa map, int dx, int dy) {
        char sgte = map.celdas[this.y + dy][this.x + dx].getTipoTerreno();
        char sgte2 = map.celdas[this.y + dy][this.x + dx].getElementoEnCelda();
        if ((sgte == ' ' || sgte == 'e' || sgte == 'L' || sgte == ',') && sgte2 == ' ') {
            char letra = map.celdas[this.y][this.x].getElementoEnCelda();
            map.celdas[this.y][this.x].setElementoEnCelda(' ');
            map.celdas[this.y][this.x].setSprite(null);
            this.x = this.x + dx;
            this.y = this.y + dy;
            map.celdas[this.y][this.x].setElementoEnCelda(letra);
            map.celdas[this.y][this.x].setSprite(sprite);
        }
    }

    public void obtener_vector_armas(ArrayList<Integer> v_armas_propias) {
//        int cant = 0;
        for (int i = 0; i < this.numPersonajes; i++) {
            for (int j = 0; j < 2; j++) {
                if (this.personajes[i].armas[j] != -1) {
//                    v_armas_propias[cant] = this.personajes[i].armas[j];
//                    cant++;
                    v_armas_propias.add(this.personajes[i].armas[j]);
                }
            }
        }
//        return cant;
    }

    public void obtener_vector_armadura(ArrayList<Integer> v_armaduras) {
//        int cant = 0;
        for (int i = 0; i < this.numPersonajes; i++) {
            if (this.personajes[i].armadura != -1) {
//                v_armaduras[cant] = this.personajes[i].armadura;
//                cant++;
                v_armaduras.add(this.personajes[i].armadura);
            }
        }
//        return cant;
    }

    public int obtener_valor_armas(ArrayList<Integer> v_armas) {
        int din = 0;
        for (int i = 0; i < v_armas.size(); i++) {
            //posi_arma = Integer.parseInt((String) v_armas.elementAt(i));
            if (v_armas.get(i) != -1) {
                din += Armeria.getArma(v_armas.get(i)).getPrecio();
            }
        }
        return din;
    }

    public int recoger_arma(ArrayList<Integer> v_armas, ArrayList<Integer> v_armaduras,/* int cant_armas, int cant_armaduras,*/ int opc) {

        ArrayList<Integer> v_armas_propias = new ArrayList();
        ArrayList<Integer> v_armaduras_propias = new ArrayList();

        ArrayList<Personaje> melees = new ArrayList();
        ArrayList<Personaje> rangos = new ArrayList();

        this.obtener_vector_armas(v_armas_propias);
        this.obtener_vector_armadura(v_armaduras_propias);

        v_armas.addAll(v_armas_propias);
        v_armaduras.addAll(v_armaduras_propias);

        //ya tenemos las armas totales
        ArrayList<Integer> armasMelee = new ArrayList();
        ArrayList<Integer> armasRango = new ArrayList();
//        int cantMelee = 0, cantRango = 0;


        //en un vector ya tenemos las armas propias y recojidas
        this.ordenar_arreglo_armas(v_armas,/* cant_armas + cant_armas_p, */ opc); //al inicio tenems las mejores armas pues nos quedaremos con las mejores
        this.ordenar_arreglo_armas(v_armaduras,/* cant_armaduras + cant_armaduras_p, */ 1);
        int cant_armas = v_armas.size();
        for (int c = 0; c < cant_armas; c++) {
            if (v_armas.get(c) == 0 || v_armas.get(c) == 2 || v_armas.get(c) == 4) {
                armasMelee.add(v_armas.get(c));
            }
            if (v_armas.get(c) == 1 || v_armas.get(c) == 3 || v_armas.get(c) == 5) {
                armasRango.add(v_armas.get(c));
            }
        }
        for (int c = 0; c < this.numPersonajes; c++) {
            //encontre el error aca, angulo no es considerado ni melee ni rango por tanto no se le llega a asignar arma, aca lo he puesto como rango, ya veremos si se cambia o no
            if (this.personajes[c] instanceof MeleePeru || this.personajes[c] instanceof MeleeRealista || this.personajes[c] instanceof EspecialMeleeRealista) {
                melees.add(this.personajes[c]);
            }
            if (this.personajes[c] instanceof RangoPeru || this.personajes[c] instanceof RangoRealista || this.personajes[c] instanceof EspecialRangoRealista || this.personajes[c] instanceof Heroe) {
                rangos.add(this.personajes[c]);
            }
        }
        //asignamos armas al batallon, primero las blanqueamos, igual con las armaduras
        for (int i = 0; i < this.numPersonajes; i++) {
            this.personajes[i].armas[0] = -1;
            this.personajes[i].armas[1] = -1;
            this.personajes[i].armadura = -1;
        }

        int j = 0;
        int cantMelee = armasMelee.size();
        int persMelee = melees.size();
        for (int i = 0; i < persMelee && j < cantMelee; i++) {
            if (melees.get(i).tipo != 1) //si no es rabona entonces le asignamos arma
            {
                melees.get(i).armas[0] = armasMelee.get(j);
                j++;
            }
        }
        //asignamos la segunda arma
        for (int i = 0; i < persMelee && j < cantMelee; i++) {
            if (melees.get(i).tipo != 1) //si no es rabona entonces le asignamos arma
            {
                melees.get(i).armas[1] = armasMelee.get(j);
                j++;
            }
        }
        int k = 0;
        int persRango = rangos.size();
        int cantRango = armasRango.size();
        for (int i = 0; i < persRango && k < cantRango; i++) {
            if (rangos.get(i).tipo != 1) //si no es rabona entonces le asignamos arma
            {
                rangos.get(i).armas[0] = armasRango.get(k);
                k++;
            }
        }
        //asignamos la segunda arma
        for (int i = 0; i < persRango && k < cantRango; i++) {
            if (rangos.get(i).tipo != 1) //si no es rabona entonces le asignamos arma
            {
                rangos.get(i).armas[1] = armasRango.get(k);
                k++;
            }
        }


        int dinero = 0;
        for (; j < cantMelee; j++) {
            if (armasMelee.get(j) != -1) {
                dinero += Armeria.getArma(armasMelee.get(j)).getPrecio();
            }
        }
        for (; k < cantRango; k++) {
            if (armasRango.get(k) != -1) {
                dinero += Armeria.getArma(armasRango.get(k)).getPrecio();
            }
        }

        //asignamos armaduras
        j = 0;
        int cant_armaduras = v_armaduras.size();
        for (int i = 0; i < this.numPersonajes && j < cant_armaduras; i++) {
            this.personajes[i].armadura = v_armaduras.get(i);
            j++;
        }
        for (; j < cant_armaduras; j++) {
            if (v_armaduras.get(j) != -1) {
                dinero += Armeria.getArma(v_armaduras.get(j)).getPrecio();
            }
        }

        this.atkTot = 0;
        this.defTot = 0;
        for (int m = 0; m < this.numPersonajes; m++) {
            this.atkTot += personajes[m].getAtk();
            this.defTot += personajes[m].getDef();
        }
        return dinero;
    }
    transient Comparator compDef = new Comparator<Integer>() {

        @Override
        public int compare(Integer a1, Integer a2) {
            return Armeria.getArma(a2).getDef() - Armeria.getArma(a1).getDef();
        }
    };
    transient Comparator compAtk = new Comparator<Integer>() {

        @Override
        public int compare(Integer a1, Integer a2) {
            return Armeria.getArma(a2).getAtk() - Armeria.getArma(a1).getAtk();
        }
    };

    private void ordenar_arreglo_armas(ArrayList<Integer> v_armas, /*int cant, */ int opc) {
        if (opc == 1) {
            Collections.sort(v_armas, compDef);
        } else {
            Collections.sort(v_armas, compAtk);
        }
    }

    public void recibir_danho(double danhoTotal, ArrayList<Integer> v_armas, ArrayList<Integer> v_armaduras/*, int[] cant_arms*/) {
        if (danhoTotal <= 0) {
            for (int i = 0; i < this.numPersonajes; i++) {
                this.personajes[i].hp -= 1;
            }
            for (int i = 0; i < this.numPersonajes; i++){
                if (this.personajes[i].hp <= 1) {
                    this.sacarPersonaje(i);
                }
            }
            if (this.numPersonajes == 0) {
                this.muerto = true;
            }
            return;
        }
        if (this.tieneHeroe) {
            danhoTotal = danhoTotal * 0.95;
        }
        int contArt = 0;
        int contMelee = 0;
        int contRango = 0;
        int contRabona = 0;
        int contHeroe = 0;
        double danho = danhoTotal;
        for (int i = 0; i < this.numPersonajes; i++) {
            if (this.personajes[i].tipo == 0) {
                contHeroe++;
            }
            if (this.personajes[i].tipo == 1) {
                contRabona++;
            }
            if (this.personajes[i].tipo == 2) {
                contArt++;
            }
            if (this.personajes[i].tipo == 3 || this.personajes[i].tipo == 5 || this.personajes[i].tipo == 7) {
                contMelee++;
            }
            if (this.personajes[i].tipo == 4 || this.personajes[i].tipo == 6 || this.personajes[i].tipo == 8) {
                contRango++;
            }
        }
        //Aqui se calcula el daÒo que recibiran las unidades de un tipo en especifico
        double danhoArt = 0;
        if (contArt != 0) {
            danhoArt = danhoTotal * 0.4 / contArt;
        }
        danho -= danhoArt;
        double danhoRabona = 0;
        if (contRabona != 0) {
            danhoRabona = danhoTotal * 0.1 / contRabona;
        }
        danho -= danhoRabona;
        double danhoMelee = 0;
        if (contMelee != 0) {
            danhoMelee = danho * 0.4 / contMelee;
        }
        danho -= danhoMelee;
        double danhoRango = 0;
        if (contRango != 0) {
            danhoRango = danho * 0.3 / contRango;
        }
        danho -= danhoRango;
        double danhoHeroe = 0;
        if (contHeroe != 0) {
            danhoHeroe = danho * 0.3 / contHeroe;
        }
        //Aqui se distribuye una porcion del daÒo a todas las unidades de un tipo por igual 60%
        for (int i = 0; i < this.numPersonajes; i++) {
            if (this.personajes[i].tipo == 0) {
                this.personajes[i].hp -= danhoHeroe / contHeroe; //generalmente habra solo 1
            }
            if (this.personajes[i].tipo == 1) {
                this.personajes[i].hp -= danhoRabona * 0.6 / contRabona;
            }
            if (this.personajes[i].tipo == 2) {
                this.personajes[i].hp -= danhoArt * 0.6 / contArt;
            }
            if (this.personajes[i].tipo == 3 || this.personajes[i].tipo == 5 || this.personajes[i].tipo == 7) {
                this.personajes[i].hp -= danhoMelee * 0.6 / contMelee;
            }
            if (this.personajes[i].tipo == 4 || this.personajes[i].tipo == 6 || this.personajes[i].tipo == 8) {
                this.personajes[i].hp -= danhoRango * 0.6 / contRango;
            }
        }
        //Aqui se distribuye el resto del daÒo a las unidades uno por uno 30%
        danhoRabona *= 0.4;
        danhoArt *= 0.4;
        danhoMelee *= 0.4;
        danhoRango *= 0.4;

        for (int i = 0; i < this.numPersonajes; i++) {
            if (this.personajes[i].tipo == 1) {
                if (this.personajes[i].hp < danhoRabona) {
                    danhoRabona -= this.personajes[i].hp;
                    this.personajes[i].hp = 0;
                } else {
                    this.personajes[i].hp -= danhoRabona;
                    danhoRabona = 0;
                }
            }
            if (this.personajes[i].tipo == 2) {
                if (this.personajes[i].hp < danhoArt) {
                    danhoArt -= this.personajes[i].hp;
                    this.personajes[i].hp = 0;
                } else {
                    this.personajes[i].hp -= danhoArt;
                    danhoArt = 0;
                }
            }
            if (this.personajes[i].tipo == 3 || this.personajes[i].tipo == 5 || this.personajes[i].tipo == 7) {
                if (this.personajes[i].hp < danhoMelee) {
                    danhoMelee -= this.personajes[i].hp;
                    this.personajes[i].hp = 0;
                } else {
                    this.personajes[i].hp -= danhoMelee;
                    danhoMelee = 0;
                }
            }
            if (this.personajes[i].tipo == 4 || this.personajes[i].tipo == 6 || this.personajes[i].tipo == 8) {
                if (this.personajes[i].hp < danhoRango) {
                    danhoRango -= this.personajes[i].hp;
                    this.personajes[i].hp = 0;
                } else {
                    this.personajes[i].hp -= danhoRango;
                    danhoRango = 0;
                }
            }
        }
        //Aqui se eliminan a las unidades muertas y se recogen sus armas
        //int [] armas = new int [90];
//        cant_arms[0] = 0; //cant armas
//        cant_arms[1] = 0; //cant armaduras
        int x = this.numPersonajes;
        for (int i = 0; i < x; i++) {
            if (this.personajes[i].hp <= 1) {
                if (this.personajes[i].armas[0] != -1) {
                    v_armas.add(this.personajes[i].armas[0]);
                }
                if (this.personajes[i].armas[1] != -1) {
                    v_armas.add(this.personajes[i].armas[1]);
                }
                if (this.personajes[i].armadura != -1) {
                    v_armaduras.add(this.personajes[i].armadura);
                }
            }
        }
        x--;
        for (int i = x; i >= 0; i--) {
            if (this.personajes[i].hp <= 1) {
                this.sacarPersonaje(i);
            }
        }
        if (this.numPersonajes == 0) {
            this.muerto = true;
        }
    }

    public Personaje detectarMasFuerte() {
        if (this.numPersonajes == 0) {
            return null;
        }
        Personaje masFuerte = this.getPersonajes()[0];
        for (int i = 1; i < this.getNumPersonajes(); i++) {
            if (masFuerte.getAtk() < this.getPersonajes()[i].getAtk()) {
                masFuerte = this.getPersonajes()[i];
            }
        }
        return masFuerte;
    }
}
